using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using System.Collections.Generic;
using System;
using System.IO;
using System.Text;
using Object = UnityEngine.Object;

namespace CGF
{
    [CustomEditor(typeof(Reference))]
    public class ReferenceEditor : Editor
    {
        public static readonly Type[] componentsMatch =
        {
            typeof(ScrollView),
            typeof(ScrollView),
            typeof(ScrollRect),
            typeof(PrizeCard),
            typeof(PrizeWheel),
            typeof(PrizeRoulette),
            typeof(TurnPage),
            typeof(FramesPlayer),
            typeof(Banner),
            typeof(CButton),
            typeof(SwitchGroup),
            typeof(Switch),
            typeof(Dropdown),
            typeof(InputField),
            typeof(CText),
            typeof(Text),
            typeof(CSlider),
            typeof(Slider),
            typeof(Toggle),
            typeof(RawImage),
            typeof(ImagePro),
            typeof(Image),
            typeof(ParticleSystem),
            typeof(Camera),
            typeof(Marquee),
            typeof(RectTransform),
            typeof(Transform)
        };

        Reference reference;
        bool haveChange;

        private void OnEnable()
        {
            reference = (Reference)target;
        }

        public override void OnInspectorGUI()
        {
            for (int i = 0; i < reference.nodes.Count; i++)
            {
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField(i.ToString(), GUILayout.MaxWidth(18));
                Reference.Node node = reference.nodes[i];

                node.obj = EditorGUILayout.ObjectField(node.obj, typeof(Object), true);
                node.isAsset = IsAsset(node.obj);
                EditorGUILayout.LabelField(GetObjectTypeName(node.obj, node.isAsset), GUILayout.MaxWidth(105));
                if (GUILayout.Button("C", GUILayout.MaxWidth(20)))
                {
                    CopyAndPaste.Copy(node.obj.name);
                    Debug.Log($"已复制对象名称:{node.obj.name}");
                }

                if (GUILayout.Button("↑", GUILayout.MaxWidth(20)))
                {
                    if (i > 0)
                    {
                        List<Reference.Node> _nodes = new List<Reference.Node>();
                        for (int j = 0; j < reference.nodes.Count; j++)
                        {
                            if (j == i - 1)
                            {
                                _nodes.Add(reference.nodes[j + 1]);
                            }
                            else if (j == i)
                            {
                                _nodes.Add(reference.nodes[j - 1]);
                            }
                            else
                            {
                                _nodes.Add(reference.nodes[j]);
                            }
                        }
                        reference.nodes = _nodes;
                        haveChange = true;
                        return;
                    }
                }

                if (GUILayout.Button("X", GUILayout.MaxWidth(20)))
                {
                    reference.nodes.RemoveAt(i);
                    haveChange = true;
                }
                EditorGUILayout.EndHorizontal();
            }

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("添加", GUILayout.MaxWidth(30));
            reference.newNode.obj = EditorGUILayout.ObjectField(reference.newNode.obj, typeof(Object), true);
            EditorGUILayout.EndHorizontal();

            if (reference.newNode.obj)
            {
                bool isAsset = IsAsset(reference.newNode.obj);
                if (!isAsset)
                {
                    for (int i = 0; i < reference.nodes.Count; i++)
                    {
                        string name = reference.newNode.obj.name;
                        if (name.Equals(reference.nodes[i].obj.name))
                        {
                            EditorUtility.DisplayDialog("提示", $"同名节点 “{name}” 已存在", "确定");
                            reference.newNode = null;
                            return;
                        }
                    }
                }
                reference.nodes.Add(reference.newNode);
                reference.newNode = null;
                haveChange = true;
            }

            //生成UI组件
            EditorGUILayout.Space();

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("生成 Partial 脚本"))
            {
                CreateComponentPartial(reference.gameObject);
            }
            EditorGUILayout.EndHorizontal();

            if (haveChange)
            {
                EditorUtility.SetDirty(target);
                haveChange = false;
            }
        }

        private static bool IsAsset(Object obj)
        {
            return obj && (AssetDatabase.IsMainAsset(obj) || obj as Sprite || obj as Mesh);
        }

        private static string GetObjectTypeName(Object obj, bool isAsset)
        {
            string typeName = "";
            if (isAsset)
            {
                if (obj is Texture2D)
                {
                    string path = AssetDatabase.GetAssetPath(obj);
                    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
                    if (importer.textureType == TextureImporterType.Sprite)
                    {
                        obj = AssetDatabase.LoadAssetAtPath<Sprite>(path);
                    }
                    typeName = $" [ Texture2D ]";
                }
                else
                {
                    typeName = $" [ {obj.GetType().Name} ]";
                }
            }
            else
            {
                foreach (Type type in componentsMatch)
                {
                    if (obj && (obj as GameObject).GetComponent(type))
                    {
                        typeName = $" [ {type.Name} ]";
                        break;
                    }
                }
            }
            return typeName;
        }

        public static void CreateComponentPartial(GameObject go)
        {
            Reference reference = go.GetComponent<Reference>();
            I18N i18n = go.GetComponent<I18N>();
            if (!reference && !i18n) return;


            string prefabFullPath = AssetDatabase.GetAssetPath(go);
            if (string.IsNullOrEmpty(prefabFullPath))
            {
                GameObject prefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(go);
                prefabFullPath = AssetDatabase.GetAssetPath(prefab);
            }
            if (string.IsNullOrEmpty(prefabFullPath))
            {
                UnityEditor.SceneManagement.PrefabStage prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetPrefabStage(go);
                if (prefabStage)
                {
                    prefabFullPath = prefabStage.assetPath;
                }
            }

            if (string.IsNullOrEmpty(prefabFullPath))
            {
                EditorUtility.DisplayDialog("提示", "只有预置体或预置体的子集才能生成", "确定");
                return;
            }

            string templatePath = $"{Application.dataPath}/{Define.ScriptsHotfixFolder}/CGFramework/UnityComponents/Reference/Editor/Templates/ComponentPartial.cs.txt";
            string partialCode = File.ReadAllText(templatePath);
            Transform rootTrans = null;
            GameObject root = PrefabUtility.GetNearestPrefabInstanceRoot(go);
            if (root)
            {
                //当前在Hierarchy窗口外部
                rootTrans = root.transform;
            }
            else
            {
                //当前双击进入预置体内部编辑
                if (GetParent(go.transform))
                {
                    rootTrans = GetParent(go.transform);
                    while (GetParent(rootTrans))
                    {
                        rootTrans = GetParent(rootTrans);
                    }
                }
            }
            bool isPrefab = !rootTrans || rootTrans == go.transform;
            if (i18n && !isPrefab)
            {
                EditorUtility.DisplayDialog("提示", "非预置体不能挂载 I18N 组件", "确定");
                return;
            }

            string saveFolder = Path.GetDirectoryName(prefabFullPath).Replace("\\", "/");
            saveFolder = saveFolder.Substring(saveFolder.IndexOf("Prefabs"));

            partialCode = partialCode.Replace("#ClassName#", go.name);
            partialCode = partialCode.Replace("#PrefabPath#", $"{saveFolder}/{go.name}");

            //属性绑定
            string properties = "";
            string propertiesBind = "";
            if (reference)
            {
                for (int i = 0; i < reference.nodes.Count; i++)
                {
                    Reference.Node node = reference.nodes[i];
                    if (!node.obj)
                    {
                        reference.nodes.RemoveAt(i);
                        CreateComponentPartial(go);
                        return;
                    }
                    string propertyName = node.obj.name.Replace(" ", "").Replace("-", "_").Replace("&", "_").Replace("(", "").Replace(")", "");
                    if (node.isAsset)
                    {
                        string typeName = node.obj.GetType().Name;
                        properties += $"\n\t\tpublic {typeName} {propertyName};";
                        propertiesBind += $"\n\t\t\t{propertyName} = reference.nodes[nodeIndex++].obj as {typeName};";
                    }
                    else
                    {
                        foreach (Type type in componentsMatch)
                        {
                            if ((node.obj as GameObject).GetComponent(type))
                            {
                                properties += $"\n\t\tpublic {type.Name} {propertyName};";
                                propertiesBind += $"\n\t\t\t{propertyName} = (reference.nodes[nodeIndex++].obj as GameObject).GetComponent<{type.Name}>();";
                                break;
                            }
                        }
                    }
                }
            }

            //i18n的方法
            string i18nFunctions = "";
            if (i18n && i18n.keys.Count > 0)
            {
                properties += "\n\t\tpublic I18N i18n;";
                propertiesBind += $"\n\t\t\ti18n = transform.GetComponent<I18N>();";

                i18nFunctions += "\n";
                foreach (var key in i18n.keys)
                {
                    i18nFunctions += "\n\t\tpublic string I18N_" + key + " { get { return i18n.GetTextByKey(\"" + key + "\"); } }";
                }
            }
            if (!string.IsNullOrEmpty(properties)) properties += "\n";
            partialCode = partialCode.Replace("#Properties#", properties);
            partialCode = partialCode.Replace("#PropertiesBind#", propertiesBind);
            partialCode = partialCode.Replace("#I18NProperties#", i18nFunctions);

            saveFolder = saveFolder.Substring("Prefabs".Length);
            saveFolder = $"{Application.dataPath}/{Define.GenerateDir}{saveFolder}";
            string savePath = $"{saveFolder}/{go.name}Partial.cs";
            SaveFile(savePath, partialCode);
            AssetDatabase.Refresh();

            Debug.Log($"生成 {go.name}Partial.cs 脚本完成");
        }

        private static Transform GetParent(Transform trans)
        {
            Transform parent = trans.parent;
            if (!parent) return null;
            if (parent.GetComponent<Canvas>())
            {
                parent = parent.parent;
            }
            return parent;
        }

        private static void SaveFile(string path, string content)
        {
            string folder = Path.GetDirectoryName(path);
            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }
            File.WriteAllText(path, content, new UTF8Encoding(false));
        }
    }
}